package au.com.mason.propertyTracker.dao;

import java.io.Serializable;
import java.math.BigDecimal;
import java.util.List;

import org.hibernate.Query;
import org.hibernate.criterion.DetachedCriteria;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
import org.springframework.stereotype.Repository;

import au.com.mason.propertyTracker.domain.Property;
import au.com.mason.propertyTracker.domain.Status;
import au.com.mason.propertyTracker.domain.Suburb;
import au.com.mason.propertyTracker.dto.SearchParameters;

@Repository
public class PropertyDAO extends HibernateDaoSupport {

	public PropertyDAO() {}
	
	public Object findById(int id) {
		return getHibernateTemplate().get(Property.class, id);
	}
	
	@SuppressWarnings("unchecked")
	public List findAll() {
        DetachedCriteria criteria = getCriteria();

        return getHibernateTemplate().findByCriteria(criteria);
    }

	protected DetachedCriteria getCriteria() {
		return DetachedCriteria.forClass(Property.class);
	}
	
	public Serializable save(Object object) {
		return getHibernateTemplate().save(object);
	}
	
	public void update(Object object) {
		if (object.getClass().getName().startsWith(Property.class.getName())) {
			getHibernateTemplate().update(object);
		}
		else {
			throw new IllegalArgumentException("expect object of type " + Property.class);
		}
	}
	
	public void delete(Object object) {
		if (object.getClass().getName().startsWith(Property.class.getName())) {
			getHibernateTemplate().delete(object);
		}
		else {
			throw new IllegalArgumentException("expect object of type " + Property.class);
		}
	}
	
	public void deleteById(Integer id) {
		Object object = findById(id);
		if (object.getClass().getName().startsWith(Property.class.getName())) {
			getHibernateTemplate().delete(object);
		}
		else {
			throw new IllegalArgumentException("expect object of type " + Property.class);
		}
	}
	
	public Property findByPropertyId(BigDecimal propertyId) {
	 	String sql = "from Property where realEstatePropertyId = :propertyId";

	 	Query query = getSession().createQuery(sql);
	 	query.setParameter("propertyId", propertyId);
       	
       	return (Property) query.uniqueResult();
	}
	
	public Property findByUrl(String url) {
	 	String sql = "from Property where url = :url";
	 	Query query = getSession().createQuery(sql);
	 	query.setParameter("url", url);
       	
       	return (Property) query.uniqueResult();
	}	
	
	public List<Property> filterProperties(Suburb suburb, SearchParameters searchParameters) {
	 	String sql = "from Property";
	 	String queryString = "";
	 	if (suburb != null) {
	 		queryString = "suburb = :suburb ";
	 	}
	 	if (searchParameters.getPriceFrom() != null) {
	 		queryString += addAnd(queryString) + ":priceFrom <= price and (priceTo is null or (priceTo is not null and :priceFrom <= priceTo)) ";
	 	}
	 	if (searchParameters.getPriceTo() != null) {
	 		queryString += addAnd(queryString) + "price <= :priceTo and (priceTo is null or (priceTo is not null and priceTo <= :priceTo)) ";
	 	}
	 	if (searchParameters.isRental()) {
	 		queryString += addAnd(queryString) + "rental = true ";
	 	}
	 	else {
	 		queryString += addAnd(queryString) + "rental = false ";
	 	}
	 	if (searchParameters.isUnderContract() || searchParameters.isRemoved() || searchParameters.isSold()) {
	 		queryString += addAnd(queryString) + "(";
	 		if (searchParameters.isUnderContract()) {
	 			queryString += "status = '" + Status.UNDER_CONTRACT + "' " + ((searchParameters.isRemoved() || searchParameters.isSold())?" or ":"");
	 		}
		 	if (searchParameters.isRemoved()) {
		 		queryString += "status = '" + Status.REMOVED + "' " + ((searchParameters.isSold())?" or ":"");
		 	}
		 	if (searchParameters.isSold()) {
		 		queryString += "status = '" + Status.SOLD + "' ";
		 	}
		 	queryString += ")";
	 	}
	 	if (searchParameters.isPriceChanged()) {
	 		queryString += addAnd(queryString) + "priceChanged = true ";
	 	}
	 	if (searchParameters.isMonitor()) {
	 		queryString += addAnd(queryString) + "monitor = true ";
	 	}
	 	else {
	 		queryString += addAnd(queryString) + "monitor = false ";
	 	}
	 	if (queryString.length() > 0) {
	 		queryString = " where " + queryString;  
	 	}

	 	System.out.println("sql - " + sql + queryString);
	 	Query query = getSession().createQuery(sql + queryString + " order by dateListed desc");
	 	if (suburb != null) {
	 		query.setParameter("suburb", suburb);
	 	}
	 	if (searchParameters.getPriceFrom() != null) {
	 		query.setParameter("priceFrom", searchParameters.getPriceFrom());
	 	}
	 	if (searchParameters.getPriceTo() != null) {
	 		query.setParameter("priceTo", searchParameters.getPriceTo());
	 	}
       	
       	return query.list();
	}
	
	private String addAnd(String queryString) {
		if (queryString.length() > 0) {
	 		return " and ";  
	 	}
		
		return "";
	}
	
}
